/*
 * Copyright (c) 2010, Petr Panteleyev
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *    3. The name of the author may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.panteleyev.blogclient;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.EventObject;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import org.panteleyev.swing.SwingFactory;
import org.panteleyev.swing.UIStrings;
import org.panteleyev.swing.UndoRedoHandler;
import org.panteleyev.swing.events.FontsUpdatedEvent;
import org.panteleyev.utilities.events.AppEventListener;

/**
 *
 * @author Petr Panteleyev <petr@panteleyev.org>
 */
class TemplateEditor extends BloggerFrame implements DocumentListener, UndoRedoHandler {
    private AbstractAction  copyAction;
    private AbstractAction  cutAction;
    private AbstractAction  pasteAction;
    private AbstractAction  saveAction;
    private AbstractAction  undoAction;
    private AbstractAction  redoAction;
    private JTextArea       textEdit;
    private JScrollPane     scroll;

    private JTextField      nameEdit;
    private JTextField      hotKeyEdit;
    private JTextField      delimEdit;
    private JTextField      descEdit;

    private final Template template;
    private int keyCode;
    private int modifiers;

    private boolean saved = true;

    private TextUndoManager textUndoManager;


    public TemplateEditor(Template t) {
        textUndoManager = new TextUndoManager(this);

        createActions();
        createMenuBar();
        initComponents();

        template = t;

        textEdit.setText(t.getBody());
        nameEdit.setText(t.getName());
        descEdit.setText(t.getDescription());
        delimEdit.setText(t.getDelimiter());
        if (t.getKeyCode() != 0) {
            keyCode = t.getKeyCode();
            modifiers = t.getModifiers();

            String modText = KeyEvent.getKeyModifiersText(t.getModifiers());
            String text = modText.replaceAll("\\+", "") + KeyEvent.getKeyText(t.getKeyCode());
            hotKeyEdit.setText(text);
        } else {
            keyCode = 0;
            modifiers = 0;
            hotKeyEdit.setText(null);
        }

        addAppEventListener(FontsUpdatedEvent.class, new AppEventListener() {
            @Override
            public void eventReceived(EventObject event) {
                onFontsUpdatedEvent();
            }
        });

        hotKeyEdit.addKeyListener(new KeyListener() {
            public void keyPressed(KeyEvent e) {
                int kc = e.getKeyCode();

                if ((kc == KeyEvent.VK_DELETE) || (kc == KeyEvent.VK_BACK_SPACE)) {
                    hotKeyEdit.setText(null);
                    keyCode = 0;
                    modifiers = 0;
                } else {
                    boolean b = ((kc >= KeyEvent.VK_0) && (kc <= KeyEvent.VK_9)) ||
                        ((kc >= KeyEvent.VK_A) && (kc <= KeyEvent.VK_Z)) ||
                        ((kc >= KeyEvent.VK_F1) && (kc <= KeyEvent.VK_F12));

                    if (b) {
                        int modi = e.getModifiers();

                        String modText = KeyEvent.getKeyModifiersText(modi);
                        String text = modText.replaceAll("\\+", "") + KeyEvent.getKeyText(kc);
                        hotKeyEdit.setText(text);

                        keyCode = kc;
                        modifiers = modi;
                    }
                }

                e.consume();
            }
            public void keyReleased(KeyEvent e) {
                e.consume();
            }
            public void keyTyped(KeyEvent e) {
                e.consume();
            }
        });

        textEdit.getDocument().addDocumentListener(this);
        nameEdit.getDocument().addDocumentListener(this);
        descEdit.getDocument().addDocumentListener(this);
        delimEdit.getDocument().addDocumentListener(this);

        /* Setup undo/redo */
        updateUndoRedo(false, false);
        textUndoManager.addComponent(textEdit);
        textUndoManager.addComponent(nameEdit);
        textUndoManager.addComponent(descEdit);
        textUndoManager.addComponent(delimEdit);

        setTitle();
    }

    public Template getTemplate() {
        return template;
    }

    private void createActions() {
        /* Edit menu */
        undoAction = new BloggingKit.UndoAction() {
            public void actionPerformed(ActionEvent e) {
                textUndoManager.undo();
            }
        };
        redoAction = new BloggingKit.RedoAction() {
            public void actionPerformed(ActionEvent e) {
                textUndoManager.redo();
            }
        };
        copyAction = new BloggingKit.CopyAction();
        cutAction = new BloggingKit.CutAction();
        pasteAction = new BloggingKit.PasteAction();
        saveAction = new SaveAction();
        saveAction.setEnabled(false);
    }

    private void createMenuBar() {
        createMenuBar(
            createMenu(UIStrings.MENU_FILE_NAME.s(), null,
                getConnectAction(),
                null,
                saveAction,
                null,
                new ExitAction()
            ),
            createMenu(UIStrings.MENU_EDIT_NAME.s(), null,
                undoAction,
                redoAction,
                null,
                cutAction,
                copyAction,
                pasteAction
            ),
            createToolsMenu(),
            createWindowMenu(),
            createHelpMenu()
        );
    }

    private void initComponents() {
        getContentPane().setLayout(new BorderLayout());

        JLabel l1, l2;
        JPanel p, p1;

        getContentPane().add(
            p1 = SwingFactory.createPanel(BorderFactory.createEmptyBorder(5, 5, 5, 5), SwingFactory.LAYOUT.BOX_Y,
                p = SwingFactory.createPanel(null, SwingFactory.LAYOUT.BOX_X,
                    SwingFactory.createToolBar(false, true,
                        saveAction,
                        null,
                        undoAction,
                        redoAction,
                        null,
                        cutAction,
                        copyAction,
                        pasteAction
                    ),
                    Box.createHorizontalGlue()
                ),
                Box.createVerticalStrut(5),
                SwingFactory.createPanel(null, SwingFactory.LAYOUT.BOX_X,
                    l1 = new JLabel(L10N.SCRIPT_EDITOR_NAME_LABEL.s()),
                    Box.createHorizontalStrut(3),
                    nameEdit = new JTextField(),
                    Box.createHorizontalStrut(5),
                    new JLabel(L10N.SCRIPT_EDITOR_DELIM_LABEL.s()),
                    Box.createHorizontalStrut(3),
                    delimEdit = new JTextField(5),
                    Box.createHorizontalStrut(5),
                    new JLabel("Hotkey:"),
                    Box.createHorizontalStrut(3),
                    hotKeyEdit = new JTextField(5)
                ),
                Box.createVerticalStrut(3),
                SwingFactory.createPanel(null, SwingFactory.LAYOUT.BOX_X,
                    l2 = new JLabel(L10N.SCRIPT_EDITOR_DESCR_LABEL.s()),
                    Box.createHorizontalStrut(3),
                    descEdit = new JTextField()
                )
            ), BorderLayout.NORTH
        );

        SwingFactory.setWidthMaximumToPreferred(p, delimEdit, hotKeyEdit);
        SwingFactory.setCommonPreferredSize(l1, l2);
        SwingFactory.setAlignmentX(p1, LEFT_ALIGNMENT);

        textEdit = new JTextArea(5, 20);
        scroll = new JScrollPane(textEdit);
        textEdit.setLineWrap(false);

        textEdit.setFont(FontManager.getEditorFont());

        getContentPane().add(scroll, BorderLayout.CENTER);

        Options.getBounds(this);
    }

    private void onFontsUpdatedEvent() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                textEdit.setFont(FontManager.getEditorFont());
            }
        });
    }

    @Override
    public void save() {
        // Check if the name is unique
        String newName = nameEdit.getText();

        if (MainClass.getTemplateManager().checkName(template, newName)) {
            template.setName(newName);
            template.setBody(textEdit.getText());
            template.setDescription(descEdit.getText());
            template.setDelimiter(delimEdit.getText());
            template.setKeyCode(keyCode);
            template.setModifiers(modifiers);

            MainClass.getTemplateManager().update(template);
            saved = true;
            saveAction.setEnabled(false);
            setTitle();
        } else {
            // say about it
            nameEdit.requestFocus();
        }
    }

    private void onTextChanged() {
        saved = false;
        saveAction.setEnabled(true);
        setTitle();
    }

    private void setTitle() {
        StringBuilder b = new StringBuilder();
        if (!saved) {
            b.append("(*) ");

        }
        b.append(L10N.SCRIPT_EDITOR_TITLE.s());

        if (!template.getName().isEmpty()) {
            b.append(" - ");
            b.append(template.getName());
        }
        setTitle(b.toString());
    }

    public void insertUpdate(DocumentEvent e) {
        onTextChanged();
    }

    public void removeUpdate(DocumentEvent e) {
        onTextChanged();
    }

    public void changedUpdate(DocumentEvent e) {
        onTextChanged();
    }

    @Override
    protected boolean canClose() {
        if (saved) {
            return true;
        } else {
            int res = JOptionPane.showConfirmDialog(this,
                "Script not saved, save?",
                AboutDialog.PRODUCT_NAME,
                JOptionPane.YES_NO_CANCEL_OPTION,
                JOptionPane.WARNING_MESSAGE);

            switch (res) {
                case JOptionPane.YES_OPTION:
                    save();
                    return saved;
                case JOptionPane.CANCEL_OPTION:
                    return false;
                case JOptionPane.NO_OPTION:
                    return true;
                default:
                    return false; // to make compiler happy
            }
        }
    }

    public void updateUndoRedo(boolean canUndo, boolean canRedo) {
        undoAction.setEnabled(canUndo);
        redoAction.setEnabled(canRedo);
    }

}
